var _ = require('lodash');
import XLog from "./XLog";
import { plus33H, minus33H, reverseHex, number2Hex, short2Hex, hex2Int, hex2float, hex2short, calcChecksum, array2Hex, CRC, getHigh, getLow, arrayPushData, Recv_Error_Def, Loop_Device_Base } from "./SerialCommon";

export const controller6wayConstant = {
    startFlag: "FF",
    reversedGroupByte: "0101",
    reversedAddressByte: "0101",
    reversedByte: "0000",
    pos_control: 2,
    pos_command: 12,
    pos_datalen: 18,
    pos_datavalue: 20,
    function_code_control: "01",    
    function_code_broadcast: "02",
    response_function_code_control: "81",    
    response_function_code_broadcast: "82",
    command_read_address: "0002",
    command_write_address: "0004",
    command_read_version: "0100",
    command_write_version: "0008",
    command_read_light_level: "1000",
    command_write_light_level: "0800",

    command_write_light:  "0001",
    command_read_light:  "0002",
    command_read_vol:  "0003",

    response_pos_address: 8,
    response_pos_command: 12,
    response_pos_datadesc: 16,
    response_pos_datavalue: 24,
}

export const response6wayType = {
    unknown: 0,
    readAddress: 1,
    readVersion: 2,
    writeVersion: 3,
    setlamplight: 4,
    readlamplight: 5,
    readLightLevel: 6,    
    writeLightLevel: 7,  
    writeAddress: 8,  
}

export class SerialController6Way{
    static generateBroadcastRequest(command, dataDesc){
        var result = new Array();
        result.push(controller6wayConstant.startFlag);                          // 插入开始帧
        result.push(controller6wayConstant.function_code_broadcast);            // 插入功能码
        result = arrayPushData(result, controller6wayConstant.reversedGroupByte);   // 保留字段(从站备用)
        result = arrayPushData(result, controller6wayConstant.reversedAddressByte);   // 保留字段(回路地址)
        result = arrayPushData(result, command);                               // 命令字段
        result = arrayPushData(result, dataDesc);                              // 数据描述字段
        
        var crc = CRC.ToModbusCRC16(result);
        result = arrayPushData(result, crc);                                   // CRC字段
        return array2Hex(result);
    }

    static generateControlRequest(address, command, dataDesc, dataValue){
        var result = new Array();
        result.push(controller6wayConstant.startFlag);                          // 插入开始帧
        result.push(controller6wayConstant.function_code_control);              // 插入功能码
        result = arrayPushData(result, controller6wayConstant.reversedByte);   // 保留字段(从站备用)
        result = arrayPushData(result, CRC.padLeft(address, 4, "0"));                               // 保留字段(回路地址)
        result = arrayPushData(result, command);                               // 命令字段
        result = arrayPushData(result, dataDesc);                              // 数据描述字段
        
        var crc = CRC.ToModbusCRC16(result);
        result = arrayPushData(result, crc);                                   // CRC字段

        if (dataValue){
            result = arrayPushData(result, dataValue);                         // 数据内容字段
            // crc = CRC.ToModbusCRC16(result);
            crc = CRC.ToModbusCRC16(arrayPushData([], dataValue));
            result = arrayPushData(result, crc);                               // CRC字段
        }
        return array2Hex(result);
    }

    static fetchResponseAddress(response){
        return response.substr(controller6wayConstant.response_pos_address, 4);
    }

    static fetchResponseCommand(response){
        return response.substr(controller6wayConstant.response_pos_command, 2);
    }

    static fetchResponseDataDesc(response){
        return response.substr(controller6wayConstant.response_pos_datadesc, 2);
    }

    static fetchResponseDataValue(response){
        return response.substr(controller6wayConstant.response_pos_datavalue, response.length - controller6wayConstant.response_pos_datavalue - 4);
    }

    static formatReadAddress(){
        return "0000";
    }

    static formatReadVersion(){
        return "0000";
    }

    static formatWriteVersion(version){
        return "00" + number2Hex(version);
    }

    static formatReadLightLevel(){
        return "0000";
    }

    static formatWriteLightLevel(level){
        return "00" + number2Hex(level);
    }

    static parserQueryDeviceAddress(response){
        return this.fetchResponseAddress(response);
    }

    static parserWriteAddress(response){
        return this.fetchResponseDataDesc(response);
    }

    static parserReadVersion(response){
        // return this.fetchResponseDataDesc(response);
        return this.fetchResponseAddress(response);
    }

    static parserWriteVersion(response){
        return this.fetchResponseDataDesc(response);
    }

    static parserReadLightLevel(response){
        return this.fetchResponseDataDesc(response);
    }

    static parserWriteLightLevel(response){
        return this.fetchResponseDataDesc(response);
    }
    
    static formatReadLight(){
        return { "dataDesc": "003F", "dataValue": null };
    }

    static formatSetLampLight(lamp){
        var dataDesc = 0;
        var dataValue = "";
        
        // 对lamp字段进行排序
        lamp = _.sortBy(lamp, function(item){
            return item['lamp'];
        })

        for(var i = 0; i < lamp.length; i++){
            var prop = lamp[i];
            if(prop.valid){
                dataDesc |= prop['valid'] << (prop['lamp'] - 1);
                dataValue = dataValue + number2Hex(prop['light']);
            }
        }
        return {
            "dataDesc": short2Hex(dataDesc),
            "dataValue": dataValue
        }
    }

    static parserSetLampLight(response){
        var result = [];
        var dataDesc = hex2short(this.fetchResponseDataDesc(response));
        // var dataValue = this.fetchResponseDataValue(response);
        for(var i = 0; i < 16; i++){
            if(dataDesc & (1<<i)){
                result.push({"lamp": i + 1, "light": 0, "valid": 0 });
            } else {
                result.push({"lamp": i + 1, "light": 0, "valid": 1 });
            }
        }
        return result;
    }

    static formatReadLampLight(){
        return {
            "dataDesc": "003F",
            "dataValue": null
        }
    }

    // 有疑问！！！TODO dataDesc值 dataValue值问题
    static parserReadLampLight(response, index){
        var result = [];
        var dataDesc = hex2short(this.fetchResponseDataDesc(response));
        var dataValue = this.fetchResponseDataValue(response);
        // for(var i = 0; i < 16; i++){
        //     let pos = result.length * 2;
        //     if(dataDesc & (1<<i)){
        //         result.push({"lamp": i + 1, "light": hex2Int(dataValue.substr(pos, 2)), "valid": 0 });
        //     } 
        // }
        for(var i = 0; i < 6; i++){
            let pos = result.length * 2;
            result.push({"lamp": i + 1 + (index-1) * Loop_Device_Base, "light": hex2Int(dataValue.substr(pos, 2)), "valid": 1 });
        }
        return result;
    }

    static getMessageType(response){
        // return response.substr(controller4wayConstant.pos_control, 2);
        var controllercode = response.substr(controller6wayConstant.pos_control, 2);
        var commandCode = response.substr(controller6wayConstant.pos_command, 4);
        if(controllercode == controller6wayConstant.response_function_code_broadcast){
            switch(commandCode){
                case controller6wayConstant.command_read_address:
                    return response6wayType.readAddress;

                case controller6wayConstant.command_read_version:
                    return response6wayType.readVersion;

                case controller6wayConstant.command_write_version:
                    return response6wayType.writeVersion;

                case controller6wayConstant.command_write_address:
                    return response6wayType.writeAddress;
            }
          
        } else if(controllercode == controller6wayConstant.response_function_code_control){
            switch(commandCode){
                case controller6wayConstant.command_read_light:
                    return response6wayType.readlamplight;

                case controller6wayConstant.command_write_light:
                    return response6wayType.setlamplight;
            }
        }else{
            XLog.e("getMessageType error: ", response);
            return response6wayType.unknown;
        }
    }

    // 12 个字节数据，包括起始码(1) + 功能码(1) + 从站地址(2) + 设备地址(2) + 命令字(2) + 数据域(2) + CRC(2)
    // 若为读取数据时，会有额外的字节包
    static checkRecvLen(msg){
        const baseLen = 12;
        if(msg.substr(0, 2) != controller6wayConstant.startFlag){
            return Recv_Error_Def.ERR_START_FLAG;
        }
        let expectLen = baseLen * 2;
        if (msg.length < expectLen){
            return Recv_Error_Def.ERR_NOT_ENOUGH_LEN;
        }

        let type = SerialController6Way.getMessageType(msg);
        if(type == response6wayType.readlamplight){
            expectLen += 8 * 2;
        }
        if (msg.length < expectLen){
            return Recv_Error_Def.ERR_NOT_ENOUGH_LEN;
        }
        
        if(CRC.ToModbusCRC16(msg.substr(0, baseLen * 2 - 4)) != msg.substr(baseLen * 2 - 4, 4)){
            console.log("loop6way checkRecvLen calc first checksum fail：", msg);
            return Recv_Error_Def.ERR_CHECKSUM;
        }
        if(expectLen > baseLen * 2 && (CRC.ToModbusCRC16(msg.substr(baseLen * 2, 12)) != msg.substr(expectLen - 4, 4))){
            console.log("loop6way checkRecvLen calc second checksum fail:", msg);
            return Recv_Error_Def.ERR_CHECKSUM;
        }
        return expectLen;
    }
}

